/*******************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.        */
/*                                                                 */
/*  NAME      = frprotocol_mng.c                                   */
/*  NOTE      = 协议库管理                                         */
/*  DATE      = 2014/10/27 yaohl                                   */
/*******************************************************************/

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <strings.h>

#include "frcomm.h"
#include "frlog.h"
#include "frmem.h"
#include "frstr.h"
#include "frconfig.h"
#include "frhash2.h"

#include "conntrack.h"
#include "frame.h"
#include "frame_params.h"
#include "frproto_mng.h"

/* 指定协议个数 */
#define APM_HASH_DEFINE_SIZE     1000

/* 已识别协议链里数据最大个数 */
#define APM_HASH_KNOWN_MAX      100000
#define APM_HASH_KNOWN_SIZE     5000

typedef struct __st_proto_mng {
    int i_is_enable;            /* 指定协议时有效 FR_YES,FR_NO */
    unsigned int ui_ver;        /* 指定协议时有效,协议版本号(更新后 +1) */
    int i_ip_proto;             /* 6(IPPROTO_TCP) / 17(IPPROTO_UDP) */
    u_int ui_ip;                /* ip 地址 */
    u_short us_port_start;      /* port 开始 */
    u_short us_port_end;        /* port 结束 */

    Frlist_header st_hdr_module_mng; /* module链表 */
} Frproto_mng;

typedef struct __st_proto_priority {
    u_short us_port_start;      /* port 开始 */
    u_short us_port_end;        /* port 结束 */

    Frmodule_mng *p_module_mng;
} Frproto_priority;

typedef struct __st_param_priority {
    Frlist_header *p_lst_hdr;
    
    int i_ip_proto;
    u_short us_port1;
    u_short us_port2;
} Frparam_priority;

/* 指定proto+ip+port的协议链 */
FR_STATIC Frhash_header *g_p_st_hash_define = NULL;

/* hash known里已经插入的数据条数 */
FR_STATIC unsigned long ul_hash_known_cnts = 0L;
/* 已识别proto+ip+port的协议链 */
FR_STATIC Frhash_header *g_p_st_hash_known = NULL;

/* 按proto+port组织的优先解析协议链 */
FR_STATIC Frlist_header *g_p_st_lst_priority = NULL;

FR_STATIC pthread_spinlock_t g_sp_lock;

/*******************************************************************************
*  FUNC     :  优先节点内存释放
*  ARGS     :  p_st_node  (Frlist_node *)
*  RTN      :
*  NOTE     :  
*******************************************************************************/
FR_STATIC void __list_node_priority_free(Frlist_node *p_st_node)
{
    if(p_st_node==NULL || p_st_node->data == NULL)
        return;
    
    frfree(p_st_node->data);
    return;
}

/*******************************************************************************
*  FUNC     :  优先节点的查找
*  ARGS     :  p_st_node       (Frlist_node *)
            :  p_compare_data  (比较用数据)
*  RTN      :  比较一致返回0，其他返回1
*  NOTE     :
*******************************************************************************/
FR_STATIC int __list_node_priority_find(Frlist_node *p_st_node, const void *p_compare_data)
{
    Frproto_priority *p_st_proto_pri_cmp, *p_st_proto_pri_node;
    
    if(!p_compare_data || p_st_node->data == NULL)
        return 1;
    
    p_st_proto_pri_cmp  = (Frproto_priority *)p_compare_data;
    p_st_proto_pri_node = (Frproto_priority *)FRLIST_GET_NODE_DATA(p_st_node);
    
    if(p_st_proto_pri_cmp->p_module_mng == NULL || p_st_proto_pri_node->p_module_mng == NULL)
        return 1;
    
    if( p_st_proto_pri_cmp->p_module_mng->st_l7_module.i_l7_proto != p_st_proto_pri_node->p_module_mng->st_l7_module.i_l7_proto)
        return 1;
    
    if(p_st_proto_pri_cmp->us_port_start >=  p_st_proto_pri_node->us_port_start
        && p_st_proto_pri_cmp->us_port_start <=  p_st_proto_pri_node->us_port_end)
        return 0;
    
    if(p_st_proto_pri_cmp->us_port_end >=  p_st_proto_pri_node->us_port_start
        && p_st_proto_pri_cmp->us_port_end <=  p_st_proto_pri_node->us_port_end )
        return 0;
    
    return 1;
}

/*******************************************************************************
*  FUNC     :  管理节点内存释放
*  ARGS     :  p_st_node  (Frlist_node *)
*  RTN      :
*  NOTE     :  
*******************************************************************************/
FR_STATIC void __hash_node_mng_free(Frlist_node *p_st_node)
{
    Frproto_mng *p_st_proto_mng;
    if(p_st_node==NULL || p_st_node->data == NULL)
        return;
        
    p_st_proto_mng = (Frproto_mng *)FRLIST_GET_NODE_DATA(p_st_node);
    frlist_remove_all(&p_st_proto_mng->st_hdr_module_mng, NULL);
    
    frfree(p_st_node->data);
    return;
}

/*******************************************************************************
*  FUNC     :  确定该协议端口是否有交叉
*  ARGS     :  p_st_node       (Frlist_node *)
            :  p_compare_data  (比较用数据)
*  RTN      :  比较一致返回0，其他返回1
*  NOTE     :
*******************************************************************************/
FR_STATIC int __hash_node_proto_port_range_exist(Frlist_node *p_st_node, const void *p_compare_data)
{
    Frproto_mng *p_st_proto_mng_cmp=NULL, *p_st_proto_mng_node=NULL;
    if(p_st_node==NULL || p_st_node->data == NULL || p_compare_data == NULL)
        return 1;
    
    p_st_proto_mng_cmp = (Frproto_mng *)p_compare_data;
    p_st_proto_mng_node = (Frproto_mng *)FRLIST_GET_NODE_DATA(p_st_node);
    
    if(p_st_proto_mng_node == NULL)
        return 1;
    
    if( (p_st_proto_mng_node->i_ip_proto & p_st_proto_mng_cmp->i_ip_proto)
        && p_st_proto_mng_node->ui_ip == p_st_proto_mng_cmp->ui_ip )
    {
         //端口起始完全一致
         if(p_st_proto_mng_cmp->us_port_start ==  p_st_proto_mng_node->us_port_start
            && p_st_proto_mng_cmp->us_port_end ==  p_st_proto_mng_node->us_port_end )
            return 1;

        //端口范围有交叉
        if(p_st_proto_mng_cmp->us_port_start >=  p_st_proto_mng_node->us_port_start
            && p_st_proto_mng_cmp->us_port_start <=  p_st_proto_mng_node->us_port_end )
            return 0;
        
        if(p_st_proto_mng_cmp->us_port_end >=  p_st_proto_mng_node->us_port_start
            && p_st_proto_mng_cmp->us_port_end <=  p_st_proto_mng_node->us_port_end )
            return 0;
    
        return 1;
    }
    else
        return 1;
}

/*******************************************************************************
*  FUNC     :  查找协议函数
*  ARGS     :  p_st_node       (Frlist_node *)
            :  p_compare_data  (比较用数据)
*  RTN      :  比较一致返回0，其他返回1
*  NOTE     :
*******************************************************************************/
FR_STATIC int __hash_node_mng_find(Frlist_node *p_st_node, const void *p_compare_data)
{
    Frproto_mng *p_st_proto_mng_cmp=NULL, *p_st_proto_mng_node=NULL;
    if(p_st_node==NULL || p_st_node->data == NULL || p_compare_data == NULL)
        return 1;
    
    p_st_proto_mng_cmp = (Frproto_mng *)p_compare_data;
    p_st_proto_mng_node = (Frproto_mng *)FRLIST_GET_NODE_DATA(p_st_node);
    
    if(p_st_proto_mng_node == NULL)
        return 1;
    
    if( (p_st_proto_mng_node->i_ip_proto & p_st_proto_mng_cmp->i_ip_proto)
        && p_st_proto_mng_node->ui_ip == p_st_proto_mng_cmp->ui_ip )
    {
        if(p_st_proto_mng_cmp->us_port_start >=  p_st_proto_mng_node->us_port_start
            && p_st_proto_mng_cmp->us_port_start <=  p_st_proto_mng_node->us_port_end )
            return 0;
        
        if(p_st_proto_mng_cmp->us_port_end >=  p_st_proto_mng_node->us_port_start
            && p_st_proto_mng_cmp->us_port_end <=  p_st_proto_mng_node->us_port_end )
            return 0;
    
        return 1;
    }
    else
        return 1;
}

/*******************************************************************************
*  FUNC     :  查找协议函数(完全一致)
*  ARGS     :  p_st_node       (Frlist_node *)
            :  p_compare_data  (比较用数据)
*  RTN      :  比较一致返回0，其他返回1
*  NOTE     :
*******************************************************************************/
FR_STATIC int __hash_node_mng_find_complete(Frlist_node *p_st_node, const void *p_compare_data)
{
    Frproto_mng *p_st_proto_mng_cmp=NULL, *p_st_proto_mng_node=NULL;
    if(p_st_node==NULL || p_st_node->data == NULL || p_compare_data == NULL)
        return 1;
    
    p_st_proto_mng_cmp = (Frproto_mng *)p_compare_data;
    p_st_proto_mng_node = (Frproto_mng *)FRLIST_GET_NODE_DATA(p_st_node);
    
    if(p_st_proto_mng_node == NULL)
        return 1;
    
    if(p_st_proto_mng_node->i_ip_proto == p_st_proto_mng_cmp->i_ip_proto 
        && p_st_proto_mng_node->ui_ip == p_st_proto_mng_cmp->ui_ip
        && p_st_proto_mng_node->us_port_start ==  p_st_proto_mng_cmp->us_port_start 
        && p_st_proto_mng_node->us_port_end ==  p_st_proto_mng_cmp->us_port_end)
        return 0;
    else
        return 1;
}

/*******************************************************************************
*  FUNC     :  节点内容出力
*  ARGS     :  p_st_node       (Frlist_node *)
            :  p_outbuff       (出力内容指针)
            :  ui_buff_size    (出力内容空间)
*  RTN      :  比较一致返回0，其他返回1
*  NOTE     :
*******************************************************************************/
FR_STATIC void __hash_node_mng_show(Frlist_node* p_st_node, char *p_outbuff, unsigned int ui_buff_size)
{
    Frproto_mng *p_st_proto_mng_node=NULL;
    char *p_outbuff_one=NULL;
    int i_outbuff_one_size =2048;

    if(p_st_node == NULL || ui_buff_size <= 0 )
        return;
    
    p_st_proto_mng_node = (Frproto_mng *)FRLIST_GET_NODE_DATA(p_st_node);
    if(p_st_proto_mng_node == NULL)
        return;
    
    p_outbuff_one = frmalloc(i_outbuff_one_size);
    if(p_outbuff_one == NULL)
        return;
    
    frlist_show(&p_st_proto_mng_node->st_hdr_module_mng, p_outbuff_one, i_outbuff_one_size, frmodule_mng_list_node_mng_show);
    
    if(p_st_proto_mng_node->ui_ip)
        snprintf(p_outbuff, ui_buff_size, "status:%s ver:%u\t%s(%s):(%i-%i)\n%s\n"
                , FR_YESNO2STR(p_st_proto_mng_node->i_is_enable), p_st_proto_mng_node->ui_ver
                , int_ntoa(p_st_proto_mng_node->ui_ip), FR_L4PROTO2STR(p_st_proto_mng_node->i_ip_proto)
                , p_st_proto_mng_node->us_port_start , p_st_proto_mng_node->us_port_end
                , p_outbuff_one);
    else
        snprintf(p_outbuff, ui_buff_size, "status:%s ver:%u\t%s (%i-%i)\n%s\n"
                , FR_YESNO2STR(p_st_proto_mng_node->i_is_enable), p_st_proto_mng_node->ui_ver
                , FR_L4PROTO2STR(p_st_proto_mng_node->i_ip_proto)
                , p_st_proto_mng_node->us_port_start , p_st_proto_mng_node->us_port_end
                , p_outbuff_one);
    
    frfree(p_outbuff_one);
    return;
}

/*******************************************************************************
*  FUNC     :  协议管理资源初始化
*  ARGS     :
*  RTN      :  FR_SUCC:成功,FR_FAIL:失败
*  NOTE     :
*******************************************************************************/
int frproto_mng_init(void)
{
    ul_hash_known_cnts = 0L;
    pthread_spin_init(&g_sp_lock, 0);

    g_p_st_hash_define = frhash2_create2(APM_HASH_DEFINE_SIZE);
    if(g_p_st_hash_define == NULL)
    {
        pthread_spin_destroy(&g_sp_lock);
        FRLOG_ERROR_DETAIL("frhash2_create2 err");
        return FR_FAIL;
    }
    
    g_p_st_hash_known= frhash2_create2(APM_HASH_KNOWN_SIZE);
    if(g_p_st_hash_known == NULL)
    {
        FRLOG_ERROR_DETAIL("frhash2_create2 err");
        goto ERROR;
    }
    
    g_p_st_lst_priority= frlist_create();
    if(g_p_st_lst_priority == NULL)
    {
        FRLOG_ERROR_DETAIL("frlist_create err");
        goto ERROR;
    }
    
    return FR_SUCC;

ERROR:
    frproto_mng_destory();
    return FR_FAIL;
}


/*******************************************************************************
*  FUNC     :  协议管理资源释放
*  ARGS     :  
*  RTN      :  
*  NOTE     :
*******************************************************************************/
void frproto_mng_destory(void)
{
    if(g_p_st_lst_priority || g_p_st_hash_known || g_p_st_hash_define)
        pthread_spin_destroy(&g_sp_lock);
    if(g_p_st_lst_priority)
        frlist_destroy(g_p_st_lst_priority, __list_node_priority_free);
    
    if(g_p_st_hash_known)
        frhash2_free2(g_p_st_hash_known, __hash_node_mng_free);

    if(g_p_st_hash_define)
        frhash2_free2(g_p_st_hash_define, __hash_node_mng_free);

    return;
}

/*******************************************************************************
*  FUNC     :  管理模块用key
*  ARGS     :  i_ip_proto  (tcp/udp)
            :  ui_ip       (ip地址)
            :  p_key       (保存地址)
            :  ui_key_size (保存地址长度)
*  RTN      :  key长度
*  NOTE     :
*******************************************************************************/
FR_STATIC int __frproto_mng_key(int i_ip_proto, u_int ui_ip, char *p_key, unsigned int ui_key_size)
{
    int i_idx=0, i_len;
    u_int *stupid_strict_aliasing_warnings=(u_int*)p_key;

    if(p_key == NULL || ui_key_size <= sizeof(int)+ sizeof(u_int))
    {
        FRLOG_ERROR_DETAIL("manager hash key err");
        return 0;
    }

    i_len = sizeof(int);
    *stupid_strict_aliasing_warnings = i_ip_proto;
    i_idx += i_len;

    i_len = sizeof(u_int);
    *(u_int *) (p_key + i_idx) = ui_ip;
    i_idx += i_len;

    //frdbg("key=%ul (value1=%u value2=%u value3=%u) len=%d\n", ul_key, ui_src, ui_dest, us_dport, i_idx);
    return i_idx;
}

/*******************************************************************************
*  FUNC     :  Mng_module模块加入到管理模块中
*  ARGS     :  p_st_hdr          (链表头节点)
            :  p_st_mng_module   (Frmodule_mng *)
*  RTN      :  FR_SUCC:成功,FR_FAIL:失败
*  NOTE     :
*******************************************************************************/
FR_STATIC int __frproto_mng_add_module(Frlist_header *p_st_hdr, Frmodule_mng *p_st_mng_module)
{
    Frlist_node* p_st_node;
    
    if(p_st_hdr == NULL || p_st_mng_module==NULL)
        return FR_FAIL;
    
    p_st_node = frlist_node_create(p_st_mng_module);
    if(p_st_node == NULL)
    {
        FRLOG_ERROR_DETAIL("frlist_node_create err");
        return FR_FAIL;
    }
    
    frlist_push(p_st_hdr, p_st_node);
    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  协议管理
*  ARGS     :  g_p_st_hash        (Frhash_header *)
            :  i_ip_proto         (tcp=6, udp=17;如果有2个,IPPROTO_TCP|IPPROTO_UDP)
            :  ui_ip              (ip 地址)
            :  us_port_start      (port 开始)
            :  us_port_end        (port 结束)
            :  i_l7_proto         (全局使用的l7代号)
*  RTN      :  0:成功; 1:失败; 2:l7协议号不存在;3:定义端口有交叉
*  NOTE     :
*******************************************************************************/
FR_STATIC int __frproto_add_list(Frhash_header *g_p_st_hash
                            , int i_ip_proto
                            , u_int ui_ip
                            , u_short us_port_start
                            , u_short us_port_end
                            , int i_l7_proto)
{
    Frmodule_mng *p_st_mng_module = NULL;
    Frlist_node *p_st_node=NULL;
    Frproto_mng st_proto_mng_cmp, *p_st_proto_mng=NULL;
    char arr_hash_key[20];
    int i_hash_key_len=0;
    int i_ret_fun=0, i_ret=1;

    if(g_p_st_hash == NULL)
        return i_ret;
    
    //l7代号转化成对应的管理节点
    p_st_mng_module = frmodule_get_module(i_l7_proto);
    if(p_st_mng_module == NULL)
        return 2;
    
    st_proto_mng_cmp.i_ip_proto = i_ip_proto;
    st_proto_mng_cmp.ui_ip = ui_ip;
    st_proto_mng_cmp.us_port_start = us_port_start;
    st_proto_mng_cmp.us_port_end = us_port_end;
    
    i_hash_key_len = __frproto_mng_key(i_ip_proto, ui_ip, arr_hash_key, sizeof(arr_hash_key));
    //确定该协议端口是否有交叉
    pthread_spin_lock(&g_sp_lock);
    p_st_node = frhash2_find_strKey(g_p_st_hash, arr_hash_key, i_hash_key_len, &st_proto_mng_cmp, __hash_node_proto_port_range_exist);
    if(p_st_node)
    {
        pthread_spin_unlock(&g_sp_lock);
        return 3;
    }
    
    p_st_node = frhash2_find_strKey(g_p_st_hash, arr_hash_key, i_hash_key_len, &st_proto_mng_cmp, __hash_node_mng_find_complete);
    //增加新节点
    if(p_st_node == NULL)
    {
        p_st_proto_mng = frmalloc(sizeof(Frproto_mng));
        if(p_st_proto_mng == NULL)
        {
            FRLOG_ERROR_DETAIL("frmalloc err");
            pthread_spin_unlock(&g_sp_lock);
            return i_ret;
        }
        p_st_proto_mng->i_is_enable = FR_NO;
        p_st_proto_mng->ui_ver = 1;
        p_st_proto_mng->i_ip_proto = i_ip_proto;
        p_st_proto_mng->ui_ip = ui_ip;
        p_st_proto_mng->us_port_start = us_port_start;
        p_st_proto_mng->us_port_end = us_port_end;
        frlist_header_init(&p_st_proto_mng->st_hdr_module_mng);
        //数据压入module链表
        i_ret_fun = __frproto_mng_add_module(&p_st_proto_mng->st_hdr_module_mng, p_st_mng_module);
        if(i_ret_fun == FR_FAIL)
        {
            pthread_spin_unlock(&g_sp_lock);
            frfree(p_st_proto_mng);
            return i_ret;
        }
        p_st_node = frlist_node_create(p_st_proto_mng);
        if(p_st_node == NULL)
        {
            FRLOG_ERROR_DETAIL("frlist_node_create err");
            pthread_spin_unlock(&g_sp_lock);
            frlist_remove_all(&p_st_proto_mng->st_hdr_module_mng, NULL);
            frfree(p_st_proto_mng);
            return i_ret;
        }

        i_hash_key_len = __frproto_mng_key(i_ip_proto, ui_ip, arr_hash_key, sizeof(arr_hash_key));
        frhash2_addStr(g_p_st_hash, arr_hash_key, i_hash_key_len, p_st_node);

        pthread_spin_unlock(&g_sp_lock);
        return 0;
    }
    
    //更新老数据
    p_st_proto_mng = (Frproto_mng *)FRLIST_GET_NODE_DATA(p_st_node);
    if(p_st_proto_mng == NULL)
    {
        pthread_spin_unlock(&g_sp_lock);
        return i_ret;
    }
    i_ret_fun = __frproto_mng_add_module(&p_st_proto_mng->st_hdr_module_mng, p_st_mng_module);
    pthread_spin_unlock(&g_sp_lock);
    if(i_ret_fun == FR_SUCC)
        i_ret = 0;
    return i_ret;
}

/*******************************************************************************
*  FUNC     :  指定协议管理
*  ARGS     :  i_ip_proto         (tcp=6, udp=17;如果有2个,IPPROTO_TCP|IPPROTO_UDP)
            :  ui_ip              (ip 地址)
            :  us_port_start      (port 开始)
            :  us_port_end        (port 结束)
            :  i_l7_proto         (全局使用的l7代号)
*  RTN      :  0:成功; 1:失败; 2:l7协议号不存在;3:定义端口有交叉
*  NOTE     :  新加协议默认不启用
*******************************************************************************/
int frproto_define_add(int i_ip_proto, u_int ui_ip, u_short us_port_start, u_short us_port_end, int i_l7_proto)
{
    if(g_p_st_hash_define == NULL)
        return 1;

    return __frproto_add_list(g_p_st_hash_define, i_ip_proto, ui_ip, us_port_start, us_port_end, i_l7_proto);
}

/*******************************************************************************
*  FUNC     :  改变指定协议状态
*  ARGS     :  i_ip_proto         (tcp=6, udp=17;如果有2个,IPPROTO_TCP|IPPROTO_UDP)
            :  ui_ip              (ip 地址)
            :  us_port_start      (port 开始)
            :  us_port_end        (port 结束)
*  RTN      :  FR_SUCC:成功,FR_FAIL:失败
*  NOTE     :  从disable->enable, 版本号增加1 (ui_ver+1)
*******************************************************************************/
FR_STATIC int __frproto_define_change_status(Frhash_header *g_p_st_hash
                                        , int i_ip_proto
                                        , u_int ui_ip
                                        , u_short us_port_start
                                        , u_short us_port_end
                                        , int i_is_enable)
{
    Frlist_node *p_st_node=NULL;
    Frproto_mng st_proto_mng_cmp, *p_st_proto_mng=NULL;
    char arr_hash_key[20];
    int i_hash_key_len=0;

    if(g_p_st_hash == NULL)
        return FR_FAIL;
    
    st_proto_mng_cmp.i_ip_proto = i_ip_proto;
    st_proto_mng_cmp.ui_ip = ui_ip;
    st_proto_mng_cmp.us_port_start = us_port_start;
    st_proto_mng_cmp.us_port_end = us_port_end;
    
    i_hash_key_len = __frproto_mng_key(i_ip_proto, ui_ip, arr_hash_key, sizeof(arr_hash_key));
    pthread_spin_lock(&g_sp_lock);
    p_st_node = frhash2_find_strKey(g_p_st_hash, arr_hash_key, i_hash_key_len, &st_proto_mng_cmp, __hash_node_mng_find_complete);
    //增加新节点
    if(p_st_node == NULL)
        goto ERROR;
    
    //更新老数据
    p_st_proto_mng = (Frproto_mng *)FRLIST_GET_NODE_DATA(p_st_node);
    if(p_st_proto_mng == NULL)
        goto ERROR;
    
    if(p_st_proto_mng->i_is_enable == i_is_enable)
    {
        pthread_spin_unlock(&g_sp_lock);
        return FR_SUCC;
    }
    
    if(i_is_enable == FR_YES)
        p_st_proto_mng->ui_ver += 1;
    p_st_proto_mng->i_is_enable = i_is_enable;
    pthread_spin_unlock(&g_sp_lock);
    return FR_SUCC;

ERROR:
    pthread_spin_unlock(&g_sp_lock);
    return FR_FAIL;
}

/*******************************************************************************
*  FUNC     :  指定协议状态可用
*  ARGS     :  i_ip_proto         (tcp=6, udp=17;如果有2个,IPPROTO_TCP|IPPROTO_UDP)
            :  ui_ip              (ip 地址)
            :  us_port_start      (port 开始)
            :  us_port_end        (port 结束)
*  RTN      :  FR_SUCC:成功,FR_FAIL:失败
*  NOTE     :  从disable->enable, ui_ver+1
*******************************************************************************/
int frproto_define_enable(int i_ip_proto
                        , u_int ui_ip
                        , u_short us_port_start
                        , u_short us_port_end)
{
    return __frproto_define_change_status(g_p_st_hash_define, i_ip_proto, ui_ip, us_port_start, us_port_end, FR_YES );
}

/*******************************************************************************
*  FUNC     :  指定协议状态不可用
*  ARGS     :  i_ip_proto         (tcp=6, udp=17;如果有2个,IPPROTO_TCP|IPPROTO_UDP)
            :  ui_ip              (ip 地址)
            :  us_port_start      (port 开始)
            :  us_port_end        (port 结束)
*  RTN      :  FR_SUCC:成功,FR_FAIL:失败
*  NOTE     :  从disable->enable, ui_ver+1
*******************************************************************************/
int frproto_define_disable(int i_ip_proto
                        , u_int ui_ip
                        , u_short us_port_start
                        , u_short us_port_end)
{
    return __frproto_define_change_status(g_p_st_hash_define, i_ip_proto, ui_ip, us_port_start, us_port_end, FR_NO );
}

/*******************************************************************************
*  FUNC     :  协议管理
*  ARGS     :  g_p_st_hash        (Frhash_header *)
            :  i_ip_proto         (tcp=6, udp=17;如果有2个,IPPROTO_TCP|IPPROTO_UDP)
            :  ui_ip              (ip 地址)
            :  us_port_start      (port 开始)
            :  us_port_end        (port 结束)
            :  i_l7_proto         (l7的管理节点)
*  RTN      :  0:成功; 1:失败; 3:定义端口有交叉
*  NOTE     :
*******************************************************************************/
FR_STATIC int __frproto_add_one(Frhash_header *g_p_st_hash, int i_ip_proto, u_int ui_ip, u_short us_port_start, u_short us_port_end, Frmodule_mng *p_st_mng_module)
{
    Frlist_node *p_st_node=NULL;
    Frproto_mng st_proto_mng_cmp, *p_st_proto_mng=NULL;
    char arr_hash_key[20];
    int i_hash_key_len=0;
    int i_ret_fun=0, i_ret=1;

    if(g_p_st_hash == NULL || p_st_mng_module == NULL)
        return i_ret;
    
    st_proto_mng_cmp.i_ip_proto = i_ip_proto;
    st_proto_mng_cmp.ui_ip = ui_ip;
    st_proto_mng_cmp.us_port_start = us_port_start;
    st_proto_mng_cmp.us_port_end = us_port_end;
    
    //确定该协议端口是否有交叉
    i_hash_key_len = __frproto_mng_key(i_ip_proto, ui_ip, arr_hash_key, sizeof(arr_hash_key));
    pthread_spin_lock(&g_sp_lock);
    p_st_node = frhash2_find_strKey(g_p_st_hash, arr_hash_key, i_hash_key_len, &st_proto_mng_cmp, __hash_node_proto_port_range_exist);
    if(p_st_node)
    {
        pthread_spin_unlock(&g_sp_lock);
        return 3;
    }
    
    p_st_node = frhash2_find_strKey(g_p_st_hash, arr_hash_key, i_hash_key_len, &st_proto_mng_cmp, __hash_node_mng_find_complete);
    //增加新节点
    if(p_st_node == NULL)
    {
        p_st_proto_mng = frmalloc(sizeof(Frproto_mng));
        if(p_st_proto_mng == NULL)
        {
            FRLOG_ERROR_DETAIL("frmalloc err");
            pthread_spin_unlock(&g_sp_lock);
            return i_ret;
        }
        p_st_proto_mng->ui_ver = 1;
        p_st_proto_mng->i_ip_proto = i_ip_proto;
        p_st_proto_mng->ui_ip = ui_ip;
        p_st_proto_mng->us_port_start = us_port_start;
        p_st_proto_mng->us_port_end = us_port_end;
        frlist_header_init(&p_st_proto_mng->st_hdr_module_mng);
        //数据压入module链表
        i_ret_fun = __frproto_mng_add_module(&p_st_proto_mng->st_hdr_module_mng, p_st_mng_module);
        if(i_ret_fun == FR_FAIL)
        {
            pthread_spin_unlock(&g_sp_lock);
            frfree(p_st_proto_mng);
            return i_ret;
        }
        p_st_node = frlist_node_create(p_st_proto_mng);
        if(p_st_node == NULL)
        {
            FRLOG_ERROR_DETAIL("frlist_node_create err");
            pthread_spin_unlock(&g_sp_lock);
            frlist_remove_all(&p_st_proto_mng->st_hdr_module_mng, NULL);
            frfree(p_st_proto_mng);
            return i_ret;
        }
        frhash2_addStr(g_p_st_hash, arr_hash_key, i_hash_key_len, p_st_node);
        pthread_spin_unlock(&g_sp_lock);
        return 0;
    }
    
    //更新老数据
    p_st_proto_mng = (Frproto_mng *)FRLIST_GET_NODE_DATA(p_st_node);
    if(p_st_proto_mng == NULL)
    {
        pthread_spin_unlock(&g_sp_lock);
        return i_ret;
    }
    //释放老协议号
    frlist_remove_all(&p_st_proto_mng->st_hdr_module_mng, NULL);
    frlist_header_init(&p_st_proto_mng->st_hdr_module_mng);
    
    i_ret_fun = __frproto_mng_add_module(&p_st_proto_mng->st_hdr_module_mng, p_st_mng_module);
    pthread_spin_unlock(&g_sp_lock);
    if(i_ret_fun == FR_SUCC)
        i_ret = 0;
    return i_ret;
}
/*******************************************************************************
*  FUNC     :  识别协议管理
*  ARGS     :  i_ip_proto         (tcp=6, udp=17;如果有2个,IPPROTO_TCP|IPPROTO_UDP)
            :  ui_ip              (ip 地址)
            :  us_port_start      (port 开始)
            :  us_port_end        (port 结束)
            :  i_l7_proto         (全局使用的l7代号)
*  RTN      :  0:成功; 1:失败; 3:定义端口有交叉
*  NOTE     :
*******************************************************************************/
int frproto_known_add(int i_ip_proto, u_int ui_ip, u_short us_port_start, u_short us_port_end, Frmodule_mng *p_st_mng_module)
{
    if(g_p_st_hash_known == NULL || p_st_mng_module == NULL)
        return 1;

    return __frproto_add_one(g_p_st_hash_known, i_ip_proto, ui_ip, us_port_start, us_port_end, p_st_mng_module);
}

/*******************************************************************************
*  FUNC     :  获取协议管理链表
*  ARGS     :  g_p_st_hash        (Frhash_header *)
            :  i_ip_proto         (tcp=6, udp=17;如果任意,IPPROTO_TCP|IPPROTO_UDP)
            :  ui_ip              (ip 地址)
            :  us_port            (port 开始)
            :  p_lst_hdr          (链表里节点存放Frmodule_mng)
            :  p_ui_ver           (不为NULL时,存放Frproto_mng.ui_ver)
*  RTN      :  FR_SUCC:成功,FR_FAIL:失败
*  NOTE     :
*******************************************************************************/
FR_STATIC int __frproto_hash_get(Frhash_header *g_p_st_hash
                           , int i_ip_proto
                           , u_int ui_ip
                           , u_short us_port
                           , int i_skip_disable
                           , Frlist_header *p_lst_hdr
                           , unsigned int *p_ui_ver)
{
    Frlist_node *p_st_node=NULL;
    Frproto_mng st_proto_mng_data, *p_st_proto_mng_node=NULL;
    char arr_hash_key[20];
    int i_hash_key_len=0;

    if(g_p_st_hash == NULL || p_lst_hdr == NULL)
        return FR_FAIL;

    st_proto_mng_data.i_ip_proto = i_ip_proto;
    st_proto_mng_data.ui_ip = ui_ip;
    st_proto_mng_data.us_port_start = us_port;
    st_proto_mng_data.us_port_end = us_port;

    //检查当前协议是否已经存在
    i_hash_key_len = __frproto_mng_key(i_ip_proto, ui_ip, arr_hash_key, sizeof(arr_hash_key));
    pthread_spin_lock(&g_sp_lock);
    p_st_node = frhash2_find_strKey(g_p_st_hash, arr_hash_key, i_hash_key_len, &st_proto_mng_data, __hash_node_mng_find);
    if(p_st_node==NULL)
    {
        pthread_spin_unlock(&g_sp_lock);
        return FR_FAIL;
    }

    p_st_proto_mng_node = (Frproto_mng *)FRLIST_GET_NODE_DATA(p_st_node);
    if( (p_st_proto_mng_node == NULL)
        || (i_skip_disable == FR_YES && p_st_proto_mng_node->i_is_enable == FR_NO ) )
    {
        pthread_spin_unlock(&g_sp_lock);
        return FR_FAIL;
    }
    
    if(p_ui_ver)
        *p_ui_ver = p_st_proto_mng_node->ui_ver;
    frlist_shallow_copy(p_lst_hdr, &p_st_proto_mng_node->st_hdr_module_mng );
    pthread_spin_unlock(&g_sp_lock);
    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  指定协议链里获取l7协议
*  ARGS     :  i_ip_proto         (tcp=6, udp=17;如果任意,IPPROTO_TCP|IPPROTO_UDP)
            :  ui_ip              (ip 地址)
            :  us_port            (port 开始)
            :  p_lst_hdr_define   (链表里节点存放Frmodule_mng)
*  RTN      :  FR_SUCC:成功,FR_FAIL:失败
*  NOTE     :  i_is_enable==FR_YES的管理链表才能获取
*******************************************************************************/
int frproto_define_get(int i_ip_proto, u_int ui_ip, u_short us_port, Frlist_header *p_lst_hdr_define, unsigned int *p_ui_ver)
{
    if(g_p_st_hash_define == NULL || p_lst_hdr_define == NULL)
        return FR_FAIL;

    return __frproto_hash_get(g_p_st_hash_define, i_ip_proto, ui_ip, us_port, FR_YES, p_lst_hdr_define, p_ui_ver);
}

/*******************************************************************************
*  FUNC     :  已识别协议链里获取l7协议
*  ARGS     :  i_ip_proto         (tcp=6, udp=17;如果任意,IPPROTO_TCP|IPPROTO_UDP)
            :  ui_ip              (ip 地址)
            :  us_port            (port 开始)
            :  p_lst_hdr_known    (链表里节点存放Frmodule_mng)
*  RTN      :  FR_SUCC:成功,FR_FAIL:失败
*  NOTE     :
*******************************************************************************/
int frproto_known_get(int i_ip_proto, u_int ui_ip, u_short us_port, Frlist_header *p_lst_hdr_known)
{
    if(g_p_st_hash_known == NULL || p_lst_hdr_known == NULL)
        return FR_FAIL;

    return __frproto_hash_get(g_p_st_hash_known, i_ip_proto, ui_ip, us_port, FR_NO, p_lst_hdr_known, NULL);
}

/*******************************************************************************
*  FUNC     :  判断指定协议链是否相同(没有发现变化)
*  ARGS     :  g_p_st_hash        (Frhash_header *)
            :  i_ip_proto         (IPPROTO_TCP,IPPROTO_UDP)
            :  ui_ip              (ip 地址)
            :  us_port            (port 开始)
            :  ui_ver             (指定协议链的版本号)
*  RTN      :  FR_SUCC:相同,FR_FAIL:不相同
*  NOTE     :
*******************************************************************************/
FR_STATIC int __frproto_is_same(Frhash_header *g_p_st_hash
                           , int i_ip_proto
                           , u_int ui_ip
                           , u_short us_port
                           , unsigned int ui_ver)
{
    Frlist_node *p_st_node=NULL;
    Frproto_mng st_proto_mng_data, *p_st_proto_mng_node=NULL;
    char arr_hash_key[20];
    int i_hash_key_len=0;

    //不应该存在这种情况
    if(g_p_st_hash == NULL )
        return FR_FAIL;

    st_proto_mng_data.i_ip_proto = i_ip_proto;
    st_proto_mng_data.ui_ip = ui_ip;
    st_proto_mng_data.us_port_start = us_port;
    st_proto_mng_data.us_port_end = us_port;

    //检查当前协议是否已经存在
    i_hash_key_len = __frproto_mng_key(i_ip_proto, ui_ip, arr_hash_key, sizeof(arr_hash_key));
    pthread_spin_lock(&g_sp_lock);
    p_st_node = frhash2_find_strKey(g_p_st_hash, arr_hash_key, i_hash_key_len, &st_proto_mng_data, __hash_node_mng_find);
    if(p_st_node==NULL) //不应该存在这种情况
    {
        pthread_spin_unlock(&g_sp_lock);
        return FR_SUCC;
    }

    p_st_proto_mng_node = (Frproto_mng *)FRLIST_GET_NODE_DATA(p_st_node);
    if( p_st_proto_mng_node && p_st_proto_mng_node->ui_ver == ui_ver )
    {
        pthread_spin_unlock(&g_sp_lock);
        return FR_SUCC;
    }
    
    pthread_spin_unlock(&g_sp_lock);
    return FR_FAIL;
}

/*******************************************************************************
*  FUNC     :  判断指定协议链是否相同(没有发现变化)
*  ARGS     :  i_ip_proto         (IPPROTO_TCP,IPPROTO_UDP)
            :  ui_ip              (ip 地址)
            :  us_port            (port 开始)
            :  ui_ver             (指定协议链的版本号)
*  RTN      :  FR_SUCC:相同,FR_FAIL:不相同
*  NOTE     :
*******************************************************************************/
int frproto_define_is_same(int i_ip_proto, u_int ui_ip, u_short us_port, unsigned int ui_ver)
{
    if(g_p_st_hash_define == NULL)
        return FR_FAIL;
    
    return __frproto_is_same(g_p_st_hash_define, i_ip_proto, ui_ip, us_port, ui_ver);
}


/*******************************************************************************
*  FUNC     :  设置按端口优先解析的协议链
*  ARGS     :  p_st_hdr           (链表头节点)
            :  us_port_start      (port 开始)
            :  us_port_end        (port 结束)
            :  i_l7_proto         (全局使用的l7代号)
*  RTN      :  FR_SUCC:成功,FR_FAIL:失败
*  NOTE     :  1.不能太多，否则有性能问题
            :  2.只支持tcp
            :  3.如果同一协议,端口有重复,覆盖原来设定
*******************************************************************************/
FR_STATIC int __frproto_pri_add(Frlist_header *p_st_hdr, u_short us_port_start, u_short us_port_end, int i_l7_proto)
{
    Frlist_node *p_st_node=NULL;
    Frproto_priority *p_st_proto_pri=NULL, st_proto_pri_find;
    Frmodule_mng *p_st_mng_module = NULL;

    if(p_st_hdr == NULL )
        return FR_FAIL;

    //l7代号转化成对应的管理节点
    p_st_mng_module = frmodule_get_module(i_l7_proto);
    if(p_st_mng_module == NULL)
        return FR_FAIL;

    //检查是否重复登入
    st_proto_pri_find.us_port_start = us_port_start;
    st_proto_pri_find.us_port_end = us_port_end;
    st_proto_pri_find.p_module_mng = p_st_mng_module;
    p_st_node = frlist_find(p_st_hdr, &st_proto_pri_find, __list_node_priority_find);
    //不存在该节点
    if(p_st_node == NULL)
    {
        p_st_proto_pri = frmalloc(sizeof(Frproto_priority));
        if(p_st_proto_pri == NULL)
            return FR_FAIL;
    
        p_st_proto_pri->us_port_start = us_port_start;
        p_st_proto_pri->us_port_end = us_port_end;
        p_st_proto_pri->p_module_mng = p_st_mng_module;
        p_st_node = frlist_node_create(p_st_proto_pri);
        if(p_st_node == NULL)
        {
            frfree(p_st_proto_pri);
            return FR_FAIL;
        }
        
        frlist_push(p_st_hdr, p_st_node);
        return FR_SUCC;
    }
    
    //更新该节点
    p_st_proto_pri = (Frproto_priority *)FRLIST_GET_NODE_DATA(p_st_node);
    p_st_proto_pri->us_port_start = us_port_start;
    p_st_proto_pri->us_port_end = us_port_end;
    
    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  设置按端口优先解析的协议链
*  ARGS     :  us_port_start      (port 开始)
            :  us_port_end        (port 结束)
            :  i_l7_proto         (全局使用的l7代号)
*  RTN      :  FR_SUCC:成功,FR_FAIL:失败
*  NOTE     :  1.不能太多，否则有性能问题
            :  2.只支持tcp
            :  3.如果同一协议,端口有重复,覆盖原来设定
*******************************************************************************/
int frproto_priority_add(u_short us_port_start, u_short us_port_end, int i_l7_proto)
{
    int i_ret = FR_FAIL;
    
    pthread_spin_lock(&g_sp_lock);
   i_ret = __frproto_pri_add(g_p_st_lst_priority, us_port_start, us_port_end, i_l7_proto);
   pthread_spin_unlock(&g_sp_lock);
   
    return i_ret;
}

/*******************************************************************************
*  FUNC     :  节点检查，并删除
*  ARGS     :  p_st_node       (Frlist_node *)
            :  p_data          (void *)
*  RTN      :
*  NOTE     :
*******************************************************************************/
FR_STATIC int __list_node_pri_del_l7_proto(Frlist_node* p_st_node, const void *p_data)
{
    Frproto_priority *p_st_proto_pri_node = NULL, *p_st_module_mng_cmp=NULL;
    int i_ret = 1;
    
    if(p_st_node==NULL || p_st_node->data == NULL || p_data == NULL)
        return i_ret;

    p_st_module_mng_cmp = (Frproto_priority *)p_data;
    if(p_st_module_mng_cmp->p_module_mng == NULL)
        return i_ret;
    //获取节点下的模块
    p_st_proto_pri_node = (Frproto_priority *)FRLIST_GET_NODE_DATA(p_st_node);
    if(p_st_proto_pri_node->p_module_mng == NULL)
        return i_ret;
    
    if(p_st_module_mng_cmp->p_module_mng->st_l7_module.i_l7_proto != p_st_proto_pri_node->p_module_mng->st_l7_module.i_l7_proto)
        return i_ret;

    frlist_node_free(g_p_st_lst_priority, p_st_node, 1, __list_node_priority_free);
    return i_ret;
}

/*******************************************************************************
*  FUNC     :  设置按端口优先解析的协议链
*  ARGS     :  i_l7_proto         (全局使用的l7代号)
*  RTN      :  FR_SUCC:成功,FR_FAIL:失败
*  NOTE     :  
*******************************************************************************/
int frproto_priority_del(int i_l7_proto)
{
    Frproto_priority st_l7_module_chk;
    Frmodule_mng st_module_mng;

    if(g_p_st_lst_priority == NULL )
        return FR_FAIL;

    //l7代号转化成对应的管理节点
    memset(&st_l7_module_chk, '\0', sizeof(Frproto_priority));
    memset(&st_module_mng, '\0', sizeof(Frmodule_mng));
    st_module_mng.st_l7_module.i_l7_proto = i_l7_proto;
    st_l7_module_chk.p_module_mng = &st_module_mng;

    pthread_spin_lock(&g_sp_lock);
    frlist_run(g_p_st_lst_priority, &st_l7_module_chk, __list_node_pri_del_l7_proto);
    pthread_spin_unlock(&g_sp_lock);
    
    return FR_SUCC;
}


/*******************************************************************************
*  FUNC     :  节点内容出力
*  ARGS     :  p_st_node       (Frlist_node *)
            :  p_outbuff       (出力内容指针)
            :  ui_buff_size    (出力内容空间)
*  RTN      :  比较一致返回0，其他返回1
*  NOTE     :
*******************************************************************************/
FR_STATIC void __list_node_pri_show(Frlist_node* p_st_node, char *p_outbuff, unsigned int ui_buff_size)
{
    Frproto_priority *p_st_proto_pri=NULL;
    L7_module *p_st_l7_module=NULL;
    
    if(p_st_node==NULL || p_st_node->data == NULL || ui_buff_size <= 0 )
        return;

    p_st_proto_pri = (Frproto_priority *)FRLIST_GET_NODE_DATA(p_st_node);
    if(p_st_proto_pri->p_module_mng == NULL)
        return;

    p_st_l7_module = &p_st_proto_pri->p_module_mng->st_l7_module;

    snprintf(p_outbuff, ui_buff_size, "port[%u-%u][%s]\tis_stub=%s l7_proto=%d ip_proto=(%d)[%s] module_name=[%s] version=[%s]\n"
        , p_st_proto_pri->us_port_start, p_st_proto_pri->us_port_end
        , p_st_proto_pri->p_module_mng->p_so_name
        , FR_YESNO2STR(p_st_proto_pri->p_module_mng->i_is_stub)
        , p_st_l7_module->i_l7_proto, p_st_l7_module->us_l4_proto, FR_L4PROTO2STR(p_st_l7_module->us_l4_proto)
        , p_st_l7_module->p_module_name, p_st_l7_module->p_version
        );
    return;
}

/*******************************************************************************
*  FUNC     :  管理模块内容出力
*  ARGS     :  
*  RTN      : 
*  NOTE     :  pp_result需要在外部释放内存
*******************************************************************************/
void frproto_priority_output(char **pp_result)
{
    char *p_outbuff=NULL;
    int i_outbuff_size =1024000;

    if(g_p_st_lst_priority == NULL)
        return;

    p_outbuff = frmalloc(i_outbuff_size);
    if(p_outbuff==NULL)
    {
        FRLOG_ERROR_DETAIL("frmalloc err");
        return;
    }

    *p_outbuff = '\0';
    
    pthread_spin_lock(&g_sp_lock);
    frlist_show(g_p_st_lst_priority, p_outbuff, i_outbuff_size, __list_node_pri_show);
    pthread_spin_unlock(&g_sp_lock);
    
    if(pp_result == NULL)
    {
        frdbg("==========================\n");
        printf("output port pri data\n%s\n", p_outbuff);
        frdbg("==========================\n");
        frfree(p_outbuff);
    }
    else
        *pp_result = p_outbuff;

    return;
}


/*******************************************************************************
*  FUNC     :  按协议(tcp/udp)和端口,获取检查链表
*  ARGS     :  p_st_node       (Frlist_node *)
            :  p_data          (void *)
*  RTN      :
*  NOTE     :
*******************************************************************************/
FR_STATIC int __list_node_pri_get_chklist(Frlist_node *p_st_node_in, const void *p_data)
{
    Frparam_priority  *p_st_param_pri=NULL;
    Frproto_priority  *p_st_proto_pri = NULL;
    L7_module    *p_st_l7_module=NULL;
    Frlist_node *p_st_node_new = NULL;
    int i_flag =FR_NO;
    
    if(p_st_node_in==NULL || p_st_node_in->data == NULL || p_data == NULL)
        return 1;

    p_st_param_pri = (Frparam_priority *)p_data;
    //获取节点下的管理模块
    p_st_proto_pri = (Frproto_priority *)FRLIST_GET_NODE_DATA(p_st_node_in);
    if(p_st_proto_pri->p_module_mng == NULL || p_st_proto_pri->p_module_mng->i_is_stub == FR_YES )
        return 1;
    
    //比较 协议(tcp/udp)
    p_st_l7_module = &p_st_proto_pri->p_module_mng->st_l7_module;
    if( (p_st_l7_module->us_l4_proto & p_st_param_pri->i_ip_proto) == 0 )
        return 1;
    
    //检查端口
    if( p_st_param_pri->us_port1 >=  p_st_proto_pri->us_port_start
        && p_st_param_pri->us_port1 <=  p_st_proto_pri->us_port_end)
        i_flag = FR_YES;
    else if( p_st_param_pri->us_port2 >=  p_st_proto_pri->us_port_start
        && p_st_param_pri->us_port2 <=  p_st_proto_pri->us_port_end)
        i_flag = FR_YES;
    if(i_flag == FR_NO )
        return 1;
    
    p_st_node_new = frlist_node_create(p_st_proto_pri->p_module_mng);
    if(p_st_node_new == NULL)
        return 1;

    frlist_push(p_st_param_pri->p_lst_hdr, p_st_node_new);
    return 1;

}

/*******************************************************************************
*  FUNC     :  管理节点查找函数
*  ARGS     :  p_st_node       (Frlist_node *)
            :  p_compare_data  (比较用数据)
*  RTN      :  比较一致返回0，其他返回1
*  NOTE     :
*******************************************************************************/
FR_STATIC int __list_node_pri_find_point(Frlist_node *p_st_node, const void *p_compare_data)
{
    if(!p_compare_data)
        return 1;
    
    if(p_compare_data == p_st_node->data)
        return 0;
    else
        return 1;
}


/*******************************************************************************
*  FUNC     :  获取协议判断模块链表
*  ARGS     :  i_ip_proto         (IPPROTO_TCP/IPPROTO_UDP)
            :  us_port1           (可能端口1)
            :  us_port2           (可能端口2)
            :  p_lst_hdr_pri      ( 优先检查协议链表 链表里节点存放Frmodule_mng)
            :  p_lst_hdr_general  ( 普通检查协议链表 链表里节点存放Frmodule_mng)
*  RTN      :  FR_SUCC:成功,FR_FAIL:失败
*  NOTE     :
*******************************************************************************/
int frproto_get_chklist(int i_ip_proto, u_short us_port1, u_short us_port2, Frlist_header *p_lst_hdr_pri, Frlist_header *p_lst_hdr_general)
{
    Frparam_priority st_param_pri;
    Frlist_node *p_st_node_pri=NULL, *p_st_node_general=NULL;
    int i_count=0, i_idx=0;
    
    if(g_p_st_lst_priority == NULL || p_lst_hdr_pri == NULL || p_lst_hdr_general == NULL)
        return FR_FAIL;

    st_param_pri.p_lst_hdr = p_lst_hdr_pri;
    st_param_pri.i_ip_proto = i_ip_proto;
    st_param_pri.us_port1 = us_port1;
    st_param_pri.us_port2 = us_port2;
    
    //按端口优先级获取检查节点
    pthread_spin_lock(&g_sp_lock);
    frlist_run(g_p_st_lst_priority, &st_param_pri, __list_node_pri_get_chklist);
    pthread_spin_unlock(&g_sp_lock);

    //按IPPROTO_TCP/IPPROTO_UDP获取需要检查的节点
    frmodule_get_chklist(i_ip_proto, p_lst_hdr_general, FR_YES);
    
    //删除优先链表里存在的节点
    if(frlist_size(p_lst_hdr_pri) <=0  || frlist_size(p_lst_hdr_general) <=0)
        return FR_SUCC;
    
    i_count = frlist_size(p_lst_hdr_pri);
    for(i_idx=0; i_idx < i_count; i_idx++)
    {
        p_st_node_pri = frlist_node_idx(p_lst_hdr_pri, i_idx);
        if(p_st_node_pri == NULL || p_st_node_pri->data == NULL)
            continue;
        p_st_node_general = frlist_find(p_lst_hdr_general, p_st_node_pri->data , __list_node_pri_find_point);
        if(p_st_node_general == NULL)
            continue;
        frlist_node_free(p_lst_hdr_general,p_st_node_general ,FR_YES , NULL);
    }
    
    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  获取 协议so:l7协议号:协议名
*  ARGS     :  p_token_lib      (解析用字符串)
*           :  pp_lib_name      (协议so)
*           :  pp_lib_l7_proto  (l7协议号)
*           :  pp_lib_module_name(协议名)
*  RTN      :  FR_SUCC
*              FR_FAIL
*  NOTE     :  函数内部没有分配内存,没有内存释放的问题
*******************************************************************************/
FR_STATIC int __frproto_cfg_get_param(char *p_token_protocol
                                     , u_short *p_us_proto
                                     , u_int *p_ui_ip
                                     , u_short *p_us_port_start
                                     , u_short *p_us_port_end
                                     , int *p_i_l7_proto)
{
    char *p_data=NULL;

    if(p_token_protocol == NULL || *p_token_protocol == '\0'
       || p_us_proto == NULL || p_ui_ip==NULL
       || p_us_port_start==NULL || p_us_port_end == NULL
       || p_i_l7_proto == NULL)
        return FR_FAIL;

    //获取协议  tcp/udp/any(tcp或udp)
    p_data = strsep(&p_token_protocol,":");
    if(p_data == NULL || *p_data == '\0')
        return FR_FAIL;
    if(strcasecmp("tcp", p_data) == 0)
        *p_us_proto = IPPROTO_TCP;
    else if(strcasecmp("udp", p_data) == 0)
        *p_us_proto = IPPROTO_UDP;
    else if(strcasecmp("any", p_data) == 0)
        *p_us_proto = IPPROTO_TCP | IPPROTO_UDP;
    else
        return FR_FAIL;

    //获取ip
    if(p_token_protocol == NULL)
        return FR_FAIL;
    p_data = strsep(&p_token_protocol,":");
    if(p_data == NULL || *p_data == '\0')
        return FR_FAIL;
    *p_ui_ip = iptools_parse_ipaddr(p_data);
    if(*p_ui_ip == 0)
        return FR_FAIL;

    //开始端口,结束端口
    if(p_token_protocol == NULL)
        return FR_FAIL;
    p_data = strsep(&p_token_protocol,":");
    if(p_data == NULL || *p_data == '\0')
        return FR_FAIL;
    iptools_parse_portrange(p_data, p_us_port_start, p_us_port_end);

    //l7协议号
    p_data = p_token_protocol;
    if(p_data == NULL || *p_data == '\0')
        return FR_FAIL;
    *p_i_l7_proto = atoi(p_data);

    return FR_SUCC;
}
/*******************************************************************************
*  FUNC     :  从配置文件中读取指定服务器的协议配置信息
*  ARGS     :  i_reload          (FR_YES:重新加载; FR_NO:不重新加载,一般程序启动时使用FR_NO)
*  RTN      :  FR_SUCC / FR_FAIL
*  NOTE     :  1. 如果增加配置，运行中更新配置文件没有问题
*           :  2. 如果有减少配置，请重新启动应用程序进行加载
*******************************************************************************/
int frproto_cfg_load(int i_reload)
{
    int i_ret_fun=0;
    char *p_protocols=NULL, *p_token_protocol=NULL;
    u_short us_proto, us_port_start, us_port_end;
    u_int ui_ip;
    int   i_l7_proto;
    char arr_one_protocol[256];
    Frhash_header *p_st_hash_define = NULL;

    //卸载协议库
    if(i_reload == FR_YES)
    {
        p_st_hash_define = frhash2_create2(APM_HASH_DEFINE_SIZE);
        if(p_st_hash_define == NULL)
        {
            FRLOG_ERROR_DETAIL("frhash2_create2 err");
            return FR_FAIL;
        }
    }
    else
        p_st_hash_define = g_p_st_hash_define;

    //加载 指定服务器的协议
    i_ret_fun = frconfig_get_string(APM_CFG_FILENAME_ANALYZER, APM_ANALYZER_KEY_PROTOCOLS_LOAD, &p_protocols);
    if(i_ret_fun != APM_FRCONFIG_SUCC || p_protocols == NULL)
    {
        FRLOG_WARN_DETAIL("open cfg[%s][%s] err", APM_CFG_FILENAME_ANALYZER, APM_ANALYZER_KEY_PROTOCOLS_LOAD);
        return FR_FAIL;
    }

    p_token_protocol = strtok(p_protocols,";");
    while(p_token_protocol != NULL)
    {
        //获取ip_proto, ip, portStart, portEnd, l7_proto
        snprintf(arr_one_protocol, sizeof(arr_one_protocol), "%s", p_token_protocol);
        i_ret_fun = __frproto_cfg_get_param(p_token_protocol, &us_proto, &ui_ip, &us_port_start, &us_port_end, &i_l7_proto);
        if(i_ret_fun== FR_FAIL)
        {
            FRLOG_WARN_DETAIL("config [%s] err", arr_one_protocol);
            //取下一个协议解析库
            p_token_protocol = strtok(NULL,";");
            continue;
        }
        //frdbg("[%s]:[%s][%s][%u-%u][%d]\n",arr_one_protocol, FR_L4PROTO2STR(us_proto), int_ntoa(ui_ip), us_port_start, us_port_end,i_l7_proto);

        i_ret_fun = __frproto_add_list(p_st_hash_define, us_proto, ui_ip, us_port_start, us_port_end, i_l7_proto);
        if(i_ret_fun == 0)
            FRLOG_INFO_DETAIL("load [%s] ok", arr_one_protocol);
        else
            FRLOG_INFO_DETAIL("load [%s] ret=%d(1:失败;2:l7协议号不存在;3:端口有交叉) fail", arr_one_protocol, i_ret_fun);

        //取下一个协议解析库
        p_token_protocol = strtok(NULL,";");
    }
    if(p_protocols)
        frfree(p_protocols);

    if(i_reload == FR_YES)
    {
        Frhash_header *p_st_hash_define_tmp = NULL;
        pthread_spin_lock(&g_sp_lock);
        p_st_hash_define_tmp = g_p_st_hash_define;
        g_p_st_hash_define = p_st_hash_define;
        pthread_spin_unlock(&g_sp_lock);
        frhash2_free2(p_st_hash_define_tmp, __hash_node_mng_free);
        FRLOG_INFO_DETAIL("reload [%s][%s]", APM_CFG_FILENAME_ANALYZER, APM_ANALYZER_KEY_PROTOCOLS_LOAD);
    }

    return FR_SUCC;
}


/*******************************************************************************
*  FUNC     :  内容出力
*  ARGS     :  g_p_st_hash        (Frhash_header *)
*  RTN      :
*  NOTE     :
*******************************************************************************/
FR_STATIC void __frproto_output(Frhash_header *g_p_st_hash, const char *p_title, char **pp_result)
{
    char *p_outbuff=NULL;
    int i_outbuff_size =1024000;

    if(g_p_st_hash == NULL)
        return;

    p_outbuff = frmalloc(i_outbuff_size);
    if(p_outbuff==NULL)
    {
        FRLOG_ERROR_DETAIL("frmalloc err");
        return;
    }

    *p_outbuff = '\0';
    pthread_spin_lock(&g_sp_lock);
    frhash2_show(g_p_st_hash, p_outbuff, i_outbuff_size, __hash_node_mng_show);
    pthread_spin_unlock(&g_sp_lock);
    if(pp_result == NULL)
    {
        //FRLOG_DEBUG("==========================");
        //FRLOG_DEBUG("output %s data start\n%s", p_title, p_outbuff);
        //FRLOG_DEBUG("==========================");
        frdbg("==========================\n");
        printf("output %s data start\n%s\n", p_title, p_outbuff);
        frdbg("==========================\n");
        frfree(p_outbuff);
    }
    else
        *pp_result = p_outbuff;
    return;
}

/*******************************************************************************
*  FUNC     :  指定协议链的内容出力
*  ARGS     : 
*  RTN      :
*  NOTE     :  pp_result需要在外部释放内存
*******************************************************************************/
void frproto_define_output(char **pp_result)
{
    if(g_p_st_hash_define == NULL)
        return;
    __frproto_output(g_p_st_hash_define, "define", pp_result);
}

/*******************************************************************************
*  FUNC     :  已识别协议链的内容出力
*  ARGS     :
*  RTN      :
*  NOTE     :  pp_result需要在外部释放内存
*******************************************************************************/
void frproto_known_output(char **pp_result)
{
    if(g_p_st_hash_known == NULL)
        return;
    __frproto_output(g_p_st_hash_known, "known", pp_result);
}

